/**
 * Copyright (c) 2010-2011 julewa.com.  
 * All rights reserved. 
 * 
 * @author Huang Benhua
 * @date 2011-2-20
 * 
**/
package com.julewa;

import java.io.PrintStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class Tester {
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ElementType.METHOD})
	public @interface test{
		public int value() default 0;
	}
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ElementType.METHOD, ElementType.TYPE})
	public @interface breakOnError{}
	//
	private static void _log(PrintStream p, String type, Object...objs){
		p.print(type);
		if(objs != null){
			for(Object o:objs)p.print(o);
		}
		p.println();
	}
	//
	private static boolean _exec(Class<?> c, Object obj){
		Method ms[] = c.getMethods();
		List<Method> methods = new ArrayList<Method>();
		for(Method m:ms){
			Class<?> cs[] = m.getParameterTypes();
			if(cs != null && cs.length > 0)continue;
			if(m.getAnnotation(Tester.test.class) == null)continue;
			methods.add(m);
		}
		Collections.sort(methods, new Comparator<Method>(){
			public int compare(Method m0, Method m1) {
				Tester.test t0 = m0.getAnnotation(Tester.test.class);
				Tester.test t1 = m1.getAnnotation(Tester.test.class);
				return t0.value() - t1.value();
			}
		});
		if(methods.isEmpty())return true;
		String head = "[TESTING][" + c.getCanonicalName() + "]";
		_log(System.out, head, "starting...");
		int ok = 0, failed = 0;
		long ctime = System.currentTimeMillis();
		for(Method m:methods){
			String mname = "[" + m.getName() + "()]";
			try {
				_log(System.out,  head, mname);
				long time = System.currentTimeMillis();
				m.invoke(obj);
				time = System.currentTimeMillis() - time;
				ok ++;
				_log(System.out,  head, mname, "OK, used time is ", time);
			} catch (Exception e) {
				failed ++;
				_log(System.err,  head, mname, "failed");
				e.printStackTrace();
				if(m.getAnnotation(Tester.breakOnError.class) == null){
					continue;
				}else break;
			}
		}
		ctime = System.currentTimeMillis() - ctime;
		_log(System.out,  head, "stopped, ", ok, " OK, ", failed, " failed, used time is ", ctime);
		return failed < 1;
	}
	//
	public static void error(Object ... objects){
		_log(System.err, "[ERROR]", objects);
	}
	public static void warn(Object ... objects){
		_log(System.err, "[WARNING]", objects);
	}
	public static void log(Object ... objects){
		_log(System.out, "[INFO]", objects);
	}
	//
	public static void execute(Class<?> ... classes){
		if(classes == null)return;
		SystemContext ctx = new SystemContext(classes);
		if(!ctx.isValid()){
			//System.out.println("Some error rising.");
			return;
		}
		//go for test
		for(Class<?> c: classes){
			Object obj = ctx.getInstanceOf(c);
			if(obj == null)continue;
			if(_exec(c, obj))continue;
			if(c.getAnnotation(Tester.breakOnError.class) != null){
				//终止执行
				break;
			}
		}
	}
}
